/* Copyright (C) 2005-2013, Unigine Corp. All rights reserved.
 *
 * File:    common_base.h
 * Desc:    Base common shader
 * Version: 1.05
 * Author:  Alexander Zapryagaev <frustum@unigine.com>
 *
 * This file is part of the Unigine engine (http://unigine.com/).
 *
 * Your use and or redistribution of this software in source and / or
 * binary form, with or without modification, is subject to: (i) your
 * ongoing acceptance of and compliance with the terms and conditions of
 * the Unigine License Agreement; and (ii) your inclusion of this notice
 * in any version of this software that you use or redistribute.
 * A copy of the Unigine License Agreement is available by contacting
 * Unigine Corp. at http://unigine.com/
 */

#ifndef __COMMON_BASE_H__
#define __COMMON_BASE_H__

/******************************************************************************\
*
* OpenGL/OpenGLES
*
\******************************************************************************/

#ifdef OPENGL || OPENGLES

/* compatibility
 */
#if SHADING_LANGUAGE >= 150
	##version 150
	#define texture2D texture
	#define texture2DProj textureProj
	#define texture3D texture
	#define textureCube texture
	#define shadow2D texture
	#define shadow2DProj textureProj
#endif

/* OpenGL
 */
#ifdef OPENGL
	#define int2 ivec2
	#define int3 ivec3
	#define int4 ivec4
	#define fixed float
	#define fixed2 vec2
	#define fixed3 vec3
	#define fixed4 vec4
	#define fixed2x2 mat2
	#define fixed3x3 mat3
	#define fixed4x4 mat4
	#define half float
	#define half2 vec2
	#define half3 vec3
	#define half4 vec4
	#define half2x2 mat2
	#define half3x3 mat3
	#define half4x4 mat4
	#define float2 vec2
	#define float3 vec3
	#define float4 vec4
	#define float2x2 mat2
	#define float3x3 mat3
	#define float4x4 mat4
	#define fmod(X,Y) mod(X,Y)
	#define frac(VALUE) fract(VALUE)
	#define lerp(X,Y,VALUE) mix(X,Y,VALUE)
	#define rsqrt(VALUE) inversesqrt(VALUE)
	#define saturate(VALUE) clamp(VALUE,0.0f,1.0f)
#endif

/* OpenGLES
 */
#ifdef OPENGLES
	#define int2 ivec2
	#define int3 ivec3
	#define int4 ivec4
	#define fixed lowp float
	#define fixed2 lowp vec2
	#define fixed3 lowp vec3
	#define fixed4 lowp vec4
	#define fixed2x2 lowp mat2
	#define fixed3x3 lowp mat3
	#define fixed4x4 lowp mat4
	#define half mediump float
	#define half2 mediump vec2
	#define half3 mediump vec3
	#define half4 mediump vec4
	#define half2x2 mediump mat2
	#define half3x3 mediump mat3
	#define half4x4 mediump mat4
	#define float2 vec2
	#define float3 vec3
	#define float4 vec4
	#define float2x2 mat2
	#define float3x3 mat3
	#define float4x4 mat4
	#define sampler2D lowp sampler2D
	#define sampler3D lowp sampler3D
	#define samplerCube lowp samplerCube
	#define sampler2DShadow lowp sampler2DShadow
	#define fmod(X,Y) mod(X,Y)
	#define frac(VALUE) fract(VALUE)
	#define lerp(X,Y,VALUE) mix(X,Y,VALUE)
	#define rsqrt(VALUE) inversesqrt(VALUE)
	#define saturate(VALUE) clamp(VALUE,0.0f,1.0f)
#endif

/* ARB uniform buffer object
 */
#ifdef USE_ARB_UNIFORM_BUFFER_OBJECT
	#define UNIFORM_BUFFER_BEGIN(NAME) uniform NAME {
	#define UNIFORM_BUFFER_END };
#else
	#define UNIFORM_BUFFER_BEGIN(NAME)
	#define UNIFORM_BUFFER_END
#endif

/* shader parameters
 */
uniform float4 s_viewport;
uniform float4 s_depth_range;
uniform fixed4 s_solid_color;
uniform fixed4 s_ambient_color;
uniform fixed4 s_environment[9];
uniform float4x4 s_projection;
uniform float4x4 s_imodelview;
uniform half3 s_camera_position;

/* shader polygon front parameters
 */
uniform half s_polygon_front;

/* shader transform parameters
 */
uniform float4 s_transform[3];

/* shader light parameters
 */
uniform half3 s_light_position;
uniform half4 s_light_positions[4];
uniform half3 s_light_direction;
uniform fixed4 s_light_color;
uniform fixed4 s_light_colors[4];
uniform half4 s_light_iradius;
uniform half4 s_light_iradiuses;
uniform half4 s_light_attenuations;
uniform half4x4 s_light_transform;
uniform half4x4 s_light_projection;
uniform fixed4 s_light_environment[9];
uniform half3 s_light_shadow_offset;
uniform half4 s_light_shadow_offsets[4];
uniform half4 s_light_shadow_iradius;
uniform half3 s_light_shadow_depth_bias;
uniform half2 s_light_shadow_depth_range;
uniform float4x4 s_light_shadow_projection;
uniform float4x4 s_light_shadow_projections[4];

/* shader scattering parameters
 */
uniform half3 s_scattering_up_direction;
uniform half3 s_scattering_light_direction;
uniform float4 s_scattering_falloff;
uniform float3 s_scattering_greenstein;
uniform float4 s_scattering_ray_beta;
uniform float4 s_scattering_mie_beta;
uniform float4 s_scattering_ray_dash;
uniform float4 s_scattering_mie_dash;
uniform half s_scattering_power;

/* shader material parameters
 */
uniform half3 s_material_detail;
uniform half3 s_material_fresnel;
uniform half4 s_material_textures[16];

/* shader material animation parameters
 */
uniform float4 s_material_animation_stem;
uniform float3 s_material_animation_leaf;
uniform float3 s_material_animation_wind;

/* shader material ambient parameters
 */
uniform half4x4 s_material_reflection_transform;
uniform half3 s_material_reflection_center;
uniform half s_material_reflection_radius;
uniform fixed3 s_material_reflection_color;

/* shader material light parameters
 */
uniform half3 s_material_shading;
uniform half4 s_material_shadings[4];
uniform half2 s_material_phong_rim;
uniform half4 s_material_anisotropy;

/* shader surface parameters
 */
uniform half4 s_surface_bound_sphere;
uniform half4 s_surface_distances;

/* shader spacer parameters
 */
uniform int2 s_spacer_num_spacers;
uniform half4 s_spacer_parameters[8];
uniform half4 s_spacer_transforms[24];

/* matrix multiplication
 */
half3 mul3(half4x4 m,half3 v) {
	return (m * float4(v,0.0f)).xyz;
}

half3 mul3(half3 v,half4x4 m) {
	return (float4(v,0.0f) * m).xyz;
}

float3 mul4(float4x4 m,float3 v) {
	return (m * float4(v,1.0f)).xyz;
}

float4 mul4(float4x4 m,float4 v) {
	return m * v;
}

/* light omni radius
 */
half3 getOmniRadius(half3 radius) {
	half3 x = s_light_transform[0].xyz;
	half3 y = s_light_transform[1].xyz;
	half3 z = s_light_transform[2].xyz;
	return float3(x * (dot(x,radius) * s_light_iradius.x) + y * (dot(y,radius) * s_light_iradius.y) + z * (dot(z,radius) * s_light_iradius.z));
}

/* light attenuation
 */
fixed getAttenuation(half radius) {
	#ifdef SHOW_LIGHTS
		fixed attenuation = 1.0f;
	#else
		fixed attenuation = saturate(radius);
		attenuation *= attenuation;
		#ifdef USE_SRGB
			attenuation *= attenuation;
		#endif
	#endif
	return attenuation;
}

/******************************************************************************\
*
* Direct3D11/Direct3D119
*
\******************************************************************************/

#elif DIRECT3D11 || DIRECT3D119

/*
 */
##pragma warning(disable : 3205 3571)

/*
 */
#define fixed half
#define fixed2 half2
#define fixed3 half3
#define fixed4 half4
#define fixed2x2 half2x2
#define fixed3x3 half3x3
#define fixed4x4 half4x4

/* shader common parameters
 */
cbuffer shader_common_parameters {
	float4 s_viewport;
	float4 s_depth_range;
	float4 s_solid_color;
	float4 s_ambient_color;
};

/* shader environment parameters
 */
cbuffer shader_environment_parameters {
	float4 s_environment[9];
};

/* shader camera parameters
 */
cbuffer shader_camera_parameters {
	float4x4 s_projection;
	float4x4 s_imodelview;
	float3 s_camera_position;
};

/* shader polygon front parameters
 */
cbuffer shader_polygon_front_parameters {
	float s_polygon_front;
};

/* shader transform parameters
 */
cbuffer shader_transform_parameter {
	float4 s_transform[3];
};

/* shader light parameters
 */
cbuffer shader_light_parameters {
	float3 s_light_position;
	float3 s_light_direction;
	float4 s_light_color;
	float4 s_light_iradius;
	float4x4 s_light_transform;
	float4x4 s_light_projection;
	float3 s_light_shadow_offset;
	float4 s_light_shadow_iradius;
	float3 s_light_shadow_depth_bias;
	float2 s_light_shadow_depth_range;
	float4x4 s_light_shadow_projection;
};

/* shader light prob parameters
 */
cbuffer shader_light_prob_parameters {
	float4 s_light_environment[9];
};

/* shader light spot parameters
 */
cbuffer shader_light_spot_parameters {
	float4 s_light_positions[4];
	float4 s_light_colors[4];
	float4 s_light_iradiuses;
	float4 s_light_attenuations;
};

/* shader light world offset parameters
 */
cbuffer shader_light_world_offset_parameters {
	float4 s_light_shadow_offsets[4];
};

/* shader light world projection parameters
 */
cbuffer shader_light_world_projection_parameters {
	float4x4 s_light_shadow_projections[4];
};

/* shader scattering parameters
 */
cbuffer shader_scattering_parameters {
	float3 s_scattering_up_direction;
	float3 s_scattering_light_direction;
	float4 s_scattering_falloff;
	float3 s_scattering_greenstein;
	float4 s_scattering_ray_beta;
	float4 s_scattering_mie_beta;
	float4 s_scattering_ray_dash;
	float4 s_scattering_mie_dash;
	float s_scattering_power;
};

/* shader material parameters
 */
cbuffer shader_material_parameters {
	float3 s_material_detail;
	float3 s_material_fresnel;
};

/* shader material textures parameters
 */
cbuffer shader_material_textures_parameters {
	float4 s_material_textures[16];
};

/* shader material tessellation parameters
 */
cbuffer shader_material_tessellation_parameters {
	float4 s_material_tessellation_factor;
	float3 s_material_tessellation_distance;
};

/* shader material animation parameters
 */
cbuffer shader_material_animation_parameters {
	float4 s_material_animation_stem;
	float3 s_material_animation_leaf;
	float3 s_material_animation_wind;
};

/* shader material ambient parameters
 */
cbuffer shader_material_ambient_parameters {
	float4x4 s_material_reflection_transform;
	float3 s_material_reflection_center;
	float3 s_material_reflection_color;
	float s_material_reflection_radius;
};

/* shader material light parameters
 */
cbuffer shader_material_light_parameters {
	float3 s_material_shading;
	float2 s_material_deferred;
	float2 s_material_phong_rim;
	float4 s_material_anisotropy;
};

/* shader material light spot parameters
 */
cbuffer shader_material_light_spot_parameters {
	float4 s_material_shadings[4];
};

/* shader surface parameters
 */
cbuffer shader_surface_parameters {
	float4 s_surface_bound_sphere;
	float4 s_surface_distances;
};

/* shader spacer parameters
 */
cbuffer shader_spacer_parameters {
	int2 s_spacer_num_spacers;
	float4 s_spacer_parameters[8];
	float4 s_spacer_transforms[24];
};

/* matrix multiplication
 */
half3 mul3(half4x4 m,half3 v) {
	return mul((half3x3)m,v);
}

half3 mul3(half3 v,half4x4 m) {
	return mul(v,(half3x3)m);
}

float3 mul4(float4x4 m,float3 v) {
	return mul(m,float4(v,1.0f)).xyz;
}

float4 mul4(float4x4 m,float4 v) {
	return mul(m,v);
}

/* light omni radius
 */
float3 getOmniRadius(float3 radius) {
	half3 x = s_light_transform._m00_m10_m20;
	half3 y = s_light_transform._m01_m11_m21;
	half3 z = s_light_transform._m02_m12_m22;
	return float3(x * (dot(x,radius) * s_light_iradius.x) + y * (dot(y,radius) * s_light_iradius.y) + z * (dot(z,radius) * s_light_iradius.z));
}

/* light attenuation
 */
half getAttenuation(half radius) {
	#ifdef SHOW_LIGHTS
		half attenuation = 1.0f;
	#else
		half attenuation = saturate(radius);
		attenuation *= attenuation;
		#ifdef USE_SRGB
			attenuation *= attenuation;
		#endif
	#endif
	return attenuation;
}

#endif

#endif /* __COMMON_BASE_H__ */
